package com.hmall.gateway.routers;

import cn.hutool.json.JSONUtil;
import com.alibaba.cloud.nacos.NacosConfigManager;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

import javax.annotation.PostConstruct;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Executor;

@Component
@Slf4j
@RequiredArgsConstructor
public class DynamicRouterLoader {
    private final NacosConfigManager nacosConfigManager;

    private final RouteDefinitionWriter writer;

    private final Set<String> routeIds = new HashSet<>();

    @PostConstruct
    public void init() throws NacosException {
        String dataId = "gateway-routes.json";
        String group = "DEFAULT_GROUP";
        //1.获取nacos配置中心连接
        ConfigService configService = nacosConfigManager.getConfigService();
        //2.监听nacos配置
        String configInfo = configService.getConfigAndSignListener(dataId, group, 500L, new Listener() {
            @Override
            public Executor getExecutor() {
                return null;
            }

            @Override
            public void receiveConfigInfo(String configInfo) {
                //路由变更时被调用，更新路由表
                updateRouterInfo(configInfo);
            }
        });
        //3.第一次加载时更新路由表
        updateRouterInfo(configInfo);

    }

    /**
     * 更新路由表信息
     * @param configInfo 最新路由表信息
     */
    private void updateRouterInfo(String configInfo) {
        log.info("监听到路由信息{}",configInfo);
        //1.删除原本路由表
        for (String routeId : routeIds) {
            writer.delete(Mono.just(routeId)).subscribe();
        }
        //2.转换路由信息
        List<RouteDefinition> routeDefinitions = JSONUtil.toList(configInfo, RouteDefinition.class);
        //3.更新路由信息
        routeIds.clear();
        for (RouteDefinition routeDefinition : routeDefinitions) {
            writer.save(Mono.just(routeDefinition)).subscribe();
            //4.保存之前的路由信息
            routeIds.add(routeDefinition.getId());
        }
    }
}
